package com.ls.fw.data.search.impl.dao.test;

import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import junit.framework.TestCase;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.QueryBuilder;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.ls.fw.data.search.impl.lucene.util.DateTools;

public class AnalyzerStudy extends TestCase{  
  
    public static void main(String[] args) throws Exception {  
        //需要处理的测试字符串  
        String str = "这是一个分词器测试程序，希望大家继续关注我的个人系列博客：基于Lucene的案例开发，这里加一点带空格的标签 LUCENE java 分词器";  
        Analyzer analyzer = null;  
        //标准分词器，如果用来处理中文，和ChineseAnalyzer有一样的效果，这也许就是之后的版本弃用ChineseAnalyzer的一个原因  
        analyzer = new StandardAnalyzer();  
        //第三方中文分词器，有下面2中构造方法。  
//        analyzer = new IKAnalyzer();  
        analyzer = new IKAnalyzer(false);  
//        analyzer = new IKAnalyzer(true);  
        //空格分词器，对字符串不做如何处理  
//        analyzer = new WhitespaceAnalyzer();  
        //简单分词器，一段一段话进行分词  
//        analyzer = new SimpleAnalyzer();  
        //二分法分词器，这个分词方式是正向退一分词(二分法分词)，同一个字会和它的左边和右边组合成一个次，每个人出现两次，除了首字和末字  
//        analyzer = new CJKAnalyzer();  
        //关键字分词器，把处理的字符串当作一个整体  
//        analyzer = new KeywordAnalyzer();  
        //被忽略的词分词器  
//        analyzer = new StopAnalyzer();  
          
        //使用分词器处理测试字符串  
        StringReader reader = new StringReader(str);  
        TokenStream  tokenStream  = analyzer.tokenStream("", reader);  
        tokenStream.reset();  
        final CharTermAttribute  term = tokenStream.getAttribute(CharTermAttribute.class);  
        int l = 0;  
        //输出分词器和处理结果  
        System.out.println(analyzer.getClass());  
        while(tokenStream.incrementToken()){    
            System.out.print(term.toString() + "|");  
            l += term.toString().length();  
            //如果一行输出的字数大于30，就换行输出  
            if (l > 30) {  
                System.out.println();  
                l = 0;  
            }  
        }  
        
        System.out.println();  
        System.out.println("d:"+DateTools.timeToString(new Date().getTime(), DateTools.Resolution.MILLISECOND));
    }  
    
    
    public static Query build(String name,String value,float boost,Analyzer analyzer){
    	Query q = null;
    	StringReader reader = new StringReader(value);  
    	QueryBuilder builder = new QueryBuilder(analyzer);
    	token(reader, analyzer, new TokenMapper() {
			
			@Override
			public void mapper(String token) {
				 System.out.println(token);
			}
		});
    	return q;
    }
    
    interface TokenMapper{
    	
    	public void mapper(String token);
    }
    
    public static void token(final StringReader reader
    		, final Analyzer analyzer, final TokenMapper mapper){
    	
    	TokenStream tokenStream  = null;
    	try {
			tokenStream = analyzer.tokenStream("", reader);  
			tokenStream.reset();  
			CharTermAttribute term = tokenStream.getAttribute(CharTermAttribute.class);  
			//输出分词器和处理结果  
			while(tokenStream.incrementToken()){    
				mapper.mapper(term.toString());
			}
		} catch (IOException e) {
			throw new IllegalArgumentException(e);
		} finally{
			if(tokenStream != null){
				try {
					tokenStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
    }
    
    @Test
    public void testStringToDate() throws ParseException {
        
        Date d = null;
        d = DateTools.stringToDate("2004");
        System.out.println(isoFormat(d));
        d = DateTools.stringToDate("20040705");
        System.out.println(isoFormat(d));
        d = DateTools.stringToDate("200407050910");
        System.out.println(isoFormat(d));
        d = DateTools.stringToDate("20040705091055990");
        System.out.println(isoFormat(d));

        try {
          d = DateTools.stringToDate("97");    // no date
        } catch(ParseException e) { /* expected exception */ }
        try {
          d = DateTools.stringToDate("200401011235009999");    // no date
        } catch(ParseException e) { /* expected exception */ }
        try {
          d = DateTools.stringToDate("aaaa");    // no date
        } catch(ParseException e) { /* expected exception */ }

      }
    public void testDateAndTimetoString() throws ParseException {
        // we use default locale since LuceneTestCase randomizes it
        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"), Locale.getDefault());
        cal.clear();
        cal.set(2004, 1, 3,   // year=2004, month=february(!), day=3
            22, 8, 56);       // hour, minute, second
        cal.set(Calendar.MILLISECOND, 333);
        
        String dateString;
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.YEAR);
        assertEquals("2004", dateString);
        assertEquals("2004-01-01 00:00:00:000", isoFormat(DateTools.stringToDate(dateString)));
        
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.MONTH);
        assertEquals("200402", dateString);
        assertEquals("2004-02-01 00:00:00:000", isoFormat(DateTools.stringToDate(dateString)));

        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.DAY);
        assertEquals("20040203", dateString);
        assertEquals("2004-02-03 00:00:00:000", isoFormat(DateTools.stringToDate(dateString)));
        
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.HOUR);
        assertEquals("2004020322", dateString);
        assertEquals("2004-02-03 22:00:00:000", isoFormat(DateTools.stringToDate(dateString)));
        
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.MINUTE);
        assertEquals("200402032208", dateString);
        assertEquals("2004-02-03 22:08:00:000", isoFormat(DateTools.stringToDate(dateString)));
        
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.SECOND);
        assertEquals("20040203220856", dateString);
        assertEquals("2004-02-03 22:08:56:000", isoFormat(DateTools.stringToDate(dateString)));
        
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.MILLISECOND);
        assertEquals("20040203220856333", dateString);
        assertEquals("2004-02-03 22:08:56:333", isoFormat(DateTools.stringToDate(dateString)));

        // date before 1970:
        cal.set(1961, 2, 5,   // year=1961, month=march(!), day=5
            23, 9, 51);       // hour, minute, second
        cal.set(Calendar.MILLISECOND, 444);
        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.MILLISECOND);
        assertEquals("19610305230951444", dateString);
        assertEquals("1961-03-05 23:09:51:444", isoFormat(DateTools.stringToDate(dateString)));

        dateString = DateTools.dateToString(cal.getTime(), DateTools.Resolution.HOUR);
        assertEquals("1961030523", dateString);
        assertEquals("1961-03-05 23:00:00:000", isoFormat(DateTools.stringToDate(dateString)));

        // timeToString:
        cal.set(1970, 0, 1, // year=1970, month=january, day=1
            0, 0, 0); // hour, minute, second
        cal.set(Calendar.MILLISECOND, 0);
        dateString = DateTools.timeToString(cal.getTime().getTime(),
            DateTools.Resolution.MILLISECOND);
        assertEquals("19700101000000000", dateString);
            
        cal.set(1970, 0, 1, // year=1970, month=january, day=1
            1, 2, 3); // hour, minute, second
        cal.set(Calendar.MILLISECOND, 0);
        dateString = DateTools.timeToString(cal.getTime().getTime(),
            DateTools.Resolution.MILLISECOND);
        assertEquals("19700101010203000", dateString);
      }
      
      public void testRound() {
        // we use default locale since LuceneTestCase randomizes it
        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"), Locale.getDefault());
        cal.clear();
        cal.set(2004, 1, 3,   // year=2004, month=february(!), day=3
            22, 8, 56);       // hour, minute, second
        cal.set(Calendar.MILLISECOND, 333);
        Date date = cal.getTime();
        assertEquals("2004-02-03 22:08:56:333", isoFormat(date));

        Date dateYear = DateTools.round(date, DateTools.Resolution.YEAR);
        assertEquals("2004-01-01 00:00:00:000", isoFormat(dateYear));

        Date dateMonth = DateTools.round(date, DateTools.Resolution.MONTH);
        assertEquals("2004-02-01 00:00:00:000", isoFormat(dateMonth));

        Date dateDay = DateTools.round(date, DateTools.Resolution.DAY);
        assertEquals("2004-02-03 00:00:00:000", isoFormat(dateDay));

        Date dateHour = DateTools.round(date, DateTools.Resolution.HOUR);
        assertEquals("2004-02-03 22:00:00:000", isoFormat(dateHour));

        Date dateMinute = DateTools.round(date, DateTools.Resolution.MINUTE);
        assertEquals("2004-02-03 22:08:00:000", isoFormat(dateMinute));

        Date dateSecond = DateTools.round(date, DateTools.Resolution.SECOND);
        assertEquals("2004-02-03 22:08:56:000", isoFormat(dateSecond));

        Date dateMillisecond = DateTools.round(date, DateTools.Resolution.MILLISECOND);
        assertEquals("2004-02-03 22:08:56:333", isoFormat(dateMillisecond));

        // long parameter:
        long dateYearLong = DateTools.round(date.getTime(), DateTools.Resolution.YEAR);
        assertEquals("2004-01-01 00:00:00:000", isoFormat(new Date(dateYearLong)));

        long dateMillisecondLong = DateTools.round(date.getTime(), DateTools.Resolution.MILLISECOND);
        assertEquals("2004-02-03 22:08:56:333", isoFormat(new Date(dateMillisecondLong)));
      }
    private String isoFormat(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS", Locale.ROOT);
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        return sdf.format(date);
      }
}  